/*
 * Copyright 2011 David de Mingo
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.shalma.internal.persistence;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.shalma.internal.reflection.IdGenerator;
import org.shalma.internal.reflection.MetaEntity;
import org.shalma.internal.reflection.MetaEntityRegistry;
import org.shalma.internal.reflection.Property;
import org.shalma.model.Entity;
import org.shalma.persistence.PersistenceException;

import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.je.DatabaseEntry;

public class EntityTupleBinding extends TupleBinding<Entity> {

	private static final byte BYTES = 0;
	private static final byte LONG = 1;
	private static final byte DOUBLE = 0;
	private static final byte BOOLEAN = 1;
	private static final byte STRING = 0;

	@Override
	public Entity entryToObject(TupleInput input) {

		MetaEntity metaEntity = MetaEntityRegistry.getInstance().getMetaEntity(
				readId(input));

		Entity entity;

		try {

			entity = (Entity) metaEntity.getConstructor().newInstance();
			input.readLong(); // version

			int numberOfProperties = input.readInt();
			for (int index = 0; index < numberOfProperties; index++) {

				Property property = metaEntity.getProperty(readId(input));
				byte type = input.readByte();
				if (property == null)
					continue; // TODO log or delete?

			}

		} catch (Exception e) {
			throw new PersistenceException(e);
		}

		return entity;
	}

	@Override
	public void objectToEntry(Entity entity, TupleOutput output) {

		MetaEntity metaEntity = MetaEntityRegistry.getInstance().getMetaEntity(
				entity);

		output.writeFast(metaEntity.getClassId());
		output.writeLong(entity.getVersion());

		List<Object> list = new ArrayList<Object>();

		for (Property property : metaEntity.getProperties()) {

			try {
				Object data = property.read(entity);

				if (data != null) {
					list.add(property.getId());
					list.add(data);
				}

			} catch (Exception e) {
				throw new PersistenceException(e);
			}
		}

		if (list.isEmpty())
			return;

		int numberOfProperties = list.size() >> 1;
		output.writeInt(numberOfProperties);

		output.getBufferLength();

		for (int index = 0; index < numberOfProperties; index++) {
			output.writeFast((byte[]) list.get(index++));
			output.writeLong(22);

		}

		// output.writeString(property.getId());
		//
		// if (data instanceof String)
		// output.writeString((String) data);
		// else
		// throw new RuntimeException("TODO");
	}

	public static byte[] getPropertyAsBytes(byte[] propertyId,
			DatabaseEntry entry) {

		byte[] propertyValue = null;

		TupleInput input = new TupleInput(entry.getData(), entry.getOffset(),
				entry.getSize());
		input.skipFast(IdGenerator.ID_BYTES_SIZE + 8);

		int numberOfProperties = input.readInt();
		for (int index = 0; index < numberOfProperties; index++) {

			byte[] targetId = readId(input);
			if (Arrays.equals(propertyId, targetId)) {
				int offset = input.readInt();
				
				break;

			} else
				input.skipFast(4); // ???
		}

		return propertyValue;
	}

	private static byte[] readId(TupleInput input) {

		byte[] id = new byte[IdGenerator.ID_BYTES_SIZE];
		input.readFast(id);

		return id;
	}
}
